#include "xfat.h"
#include "stdlib.h"

extern uint8_t temp_buf[];

static xfat_err_t parse_fat_header(xfat_t *xfat, dbr_t *dbr);
static uint32_t cluster_first_sector(xfat_t *xfat, uint32_t cluster_no);
static xfat_err_t open_sub_file(xfat_t *xfat, uint32_t dir_cluster, xfile_t *file, const char *path);
static const char *skip_first_path_sep(const char *path);
static xfat_err_t locate_file_dir_item(xfat_t *xfat, uint32_t *dir_cluster, uint32_t *cluster_offset, const char *path, uint32_t *move_bytes, dir_item_t **r_dir_item);

/**
 * @brief  检查簇是否可用，非占用或坏簇
 * @param  cluster           待检查的簇
 * @return xfat_err_t        簇可用 - (1) 簇不可用 - (0)
 */
xfat_err_t is_cluster_valid(uint32_t cluster)
{
    uint32_t clu_temp = cluster & 0x0FFFFFFF;

    // 簇号有效值应在 0x0FFF FFF0 - 0x0000 0002之间
    return ((clu_temp < 0x0FFFFFF0) &&
            (clu_temp >= 0x2));
}

/**
 * @brief  获取指定簇的下一个簇号
 * @param  xfat              FAT对象
 * @param  curr_cluster_no   当前簇号
 * @param  next_cluster_no   [out]下一簇号
 * @return xfat_err_t        获取成功 - (0)
 */
xfat_err_t get_next_cluster(xfat_t *xfat,
                            uint32_t curr_cluster_no,
                            uint32_t *next_cluster_no)
{
    cluster32_t *cluster32_buf = NULL;
    if (is_cluster_valid(curr_cluster_no) == 1)
    {
        // 检查当前簇号为有效的簇号
        cluster32_buf = (cluster32_t *)xfat->fat_tbl_buf;
        *next_cluster_no = cluster32_buf[curr_cluster_no].v;
    }
    else
    {
        *next_cluster_no = CLUSTER_INVALID;
    }

    return FS_ERR_OK;
}

/**
 * @brief 打开FAT32分区
 *
 * @param xfat [out]FAT描述对象
 * @param xdisk_part [in]分区描述对象
 * @return xfat_err_t
 */
xfat_err_t xfat_open(xfat_t *xfat,
                     xdisk_part_t *xdisk_part)
{
    dbr_t *dbr_buf = (dbr_t *)temp_buf;
    xdisk_t *xdisk = xdisk_part->disk;
    xfat_err_t err = FS_ERR_OK;

    xfat->disk_part = xdisk_part;
    err = xdisk_read_sector(xdisk, (uint8_t *)dbr_buf, xdisk_part->start_sector, 1);
    if (err < 0)
    {
        return err;
    }

    err = parse_fat_header(xfat, dbr_buf);
    if (err < 0)
    {
        return err;
    }

    // 获取完整的FAT表
    xfat->fat_tbl_buf = (uint8_t *)malloc(xfat->fat_tbl_sectors * xdisk->sector_size);
    if (xfat->fat_tbl_buf != NULL)
    {
        // 读取完整的FAT表
        err = xdisk_read_sector(xdisk,
                                xfat->fat_tbl_buf,
                                xfat->fat_start_sector,
                                xfat->fat_tbl_sectors);
        if (err < 0)
        {
            return err;
        }
    }

    return FS_ERR_OK;
}

/**
 * @brief  读一个簇
 * @param  xfat              xfat描述对象
 * @param  buf               簇缓冲区
 * @param  start_cluster_num 起始簇号
 * @param  cluster_cnt       读取的簇个数
 * @return xfat_err_t        成功 - (0)
 */
xfat_err_t read_cluster(xfat_t *xfat,
                        uint8_t *buf,
                        uint32_t start_cluster_num,
                        uint32_t cluster_cnt)
{
    xfat_err_t err = FS_ERR_OK;
    uint8_t *curr_buf = buf;
    uint32_t curr_sector = 0;

    // 获取该簇的第一个扇区号
    curr_sector = cluster_first_sector(xfat, start_cluster_num);

    for (int i = 0; i < cluster_cnt; i++)
    {
        // 读取该簇的数据 起始簇号前面已经获取 每个簇的扇区数在xfat中有
        err = xdisk_read_sector(xfat->disk_part->disk,
                                curr_buf,
                                curr_sector,
                                xfat->sec_per_cluster);
        if (err < 0)
        {
            return err;
        }

        curr_buf += xfat->cluster_byte_size;
        curr_sector += xfat->sec_per_cluster;
    }
    return FS_ERR_OK;
}

/**
 * @brief  brief_temp
 * @param  xfat              param_temp
 * @param  file              param_temp
 * @param  path              param_temp
 * @return xfat_err_t        return_temp
 */
xfat_err_t xfile_open(xfat_t *xfat,
                      xfile_t *file,
                      const char *path)
{
    return open_sub_file(xfat, xfat->root_cluster, file, path);
}

/**
 * @brief  brief_temp
 * @param  file              param_temp
 * @return xfat_err_t        return_temp
 */
xfat_err_t xfile_close(xfile_t *file)
{
    return FS_ERR_OK;
}

/**
 * @brief 通过DBR解析FAT信息
 *
 * @param xfat [out]FAT描述对象
 * @param dbr [in]FAT文件系统DBR
 * @return xfat_err_t
 */
static xfat_err_t parse_fat_header(xfat_t *xfat, dbr_t *dbr)
{
    xdisk_part_t *xdisk_part = xfat->disk_part;
    uint32_t fat_table_num = 0; // 活动FAT表项ID

    // 解析FAT表占用扇区数 根目录所在簇
    xfat->fat_tbl_sectors = dbr->fat32.bpb_fat_size32;
    xfat->root_cluster = dbr->fat32.bpb_root_clus;

    // 解析FAT表起始扇区 FAT表数量
    if ((dbr->fat32.bpb_ext_flags & (1 << 7)) != 0)
    {
        // 1000 xxxx
        // 不开启镜像 1000 xxxx (xxxx)表示使用哪个FAT表
        fat_table_num = dbr->fat32.bpb_ext_flags & 0xF;
        // |start_sector|rsvd_sector|table * table_sector|
        // 起始扇区号 + 保留扇区数 + (指定FAT分区表号 * 单个FAT表扇区数)
        xfat->fat_start_sector = xdisk_part->start_sector + dbr->bpb.bpb_rsvd_sec_cnt + (fat_table_num * dbr->fat32.bpb_fat_size32);
        // 活动FAT分区表数量 指定为1
        xfat->fat_tbl_nr = 1;
    }
    else
    {
        // 0000 xxxx
        // 开启镜像 需要实时镜像到每一个FAT表
        // 起始扇区号 + 保留扇区数
        xfat->fat_start_sector = xdisk_part->start_sector + dbr->bpb.bpb_rsvd_sec_cnt;
        // 活动分区表数量 记录在DBR中
        xfat->fat_tbl_nr = dbr->bpb.bpb_num_fats;
    }

    // 总扇区数
    xfat->total_sectors = dbr->bpb.bpb_tot_sec32;
    // 每簇扇区数
    xfat->sec_per_cluster = dbr->bpb.bpb_sec_per_clus;
    // 每簇字节数 每簇扇区数 * 每扇区字节数
    xfat->cluster_byte_size = dbr->bpb.bpb_sec_per_clus * dbr->bpb.bpb_byts_per_sec;
    return FS_ERR_OK;
}

/**
 * @brief  获取指定簇的第一个扇区编号
 * @param  xfat              fat描述对象
 * @param  cluster_no        簇号
 * @return uint32_t          扇区号
 */
static uint32_t cluster_first_sector(xfat_t *xfat,
                                     uint32_t cluster_no)
{
    uint32_t data_start_sector = 0; // FAT文件系统数据区起始扇区
    // FAT表起始扇区号 +　(单个FAT表扇区数 * FAT表个数)
    data_start_sector = xfat->fat_start_sector + (xfat->fat_tbl_sectors * xfat->fat_tbl_nr);

    // 数据区第一个扇区号 + (绝对扇区号 * 每个簇的扇区数)
    return data_start_sector + ((cluster_no - 2) * xfat->sec_per_cluster);
}

/**
 * @brief  打开指定dir_cluster开始的簇链中包含的子文件 如果path为空则以dir_cluster创建一个开开的目录对象
 * @param  xfat              xfat对象
 * @param  dir_cluster       查找的顶层目录的其实簇链
 * @param  file              打开的文件file结构
 * @param  path              以die_cluster所对应的目录为起点的完整路径
 * @return xfat_err_t        return_temp
 */
static xfat_err_t open_sub_file(xfat_t *xfat,
                                uint32_t dir_cluster,
                                xfile_t *file,
                                const char *path)
{
    const char *act_path = NULL;     // 实际的路径
    dir_item_t *dir_item = NULL;     // 目录项指针
    uint32_t file_start_cluster = 0; // 文件其实簇号
    const char *curr_path = NULL;    // 当前路径指针

    act_path = skip_first_path_sep(path);

    // 如果传入路径不为空 则查看子目录
    // 否则直接认为dir_cluster指向的是一个目录 用于打开根目录
    if ((act_path != NULL) && (*act_path != '\0'))
    {
        curr_path = act_path;
        while (curr_path != NULL)
        {
        }
    }
    else
    {
        // size
        // type
        // start_cluster
        // curr_cluster
    }

    file->attr = 0;

    file->size = 0;
    file->type = FAT_DIR;
    file->start_cluster = dir_cluster;
    file->curr_cluster = dir_cluster;

    file->xfat = xfat;
    file->pos = 0;
    file->err = FS_ERR_OK;
    return FS_ERR_OK;
}

/**
 * @brief  跳过开头的分隔符
 * @param  path              目标路径
 * @return const char*       return_temp
 */
static const char *skip_first_path_sep(const char *path)
{
    const char *c = path;

    while ((*c == '\\') || (*c == '/'))
    {
        c++;
    }
    return c;
}

/**
 * @brief  brief_temp
 * @param  xfat              param_temp
 * @param  dir_cluster       param_temp
 * @param  cluster_offset    param_temp
 * @param  path              param_temp
 * @param  move_bytes        param_temp
 * @param  r_dir_item        param_temp
 * @return xfat_err_t        return_temp
 */
static xfat_err_t locate_file_dir_item(xfat_t *xfat,
                                       uint32_t *dir_cluster,
                                       uint32_t *cluster_offset,
                                       const char *path,
                                       uint32_t *move_bytes,
                                       dir_item_t **r_dir_item)
{
}
